﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Driver;
using System.Configuration;

namespace MongoServices
{
	/// <summary>
	/// The base MongoServices repository.
	/// </summary>
	/// <typeparam name="T">The MongoServices model to be used by this repository.</typeparam>
	public abstract class MongoServicesRepository<T> : IMongoServicesRepository<T>
		where T : MongoServicesModel
	{
		#region Private Fields
		private MongoCollection<T> _collection;
		#endregion

		#region Protected Properties
		/// <summary>
		/// Gets the name of the mongoDB collection to use.
		/// </summary>
		protected virtual string CollectionName
		{
			get
			{
				var attr = typeof(T).GetCustomAttribute<MongoCollectionNameAttribute>(true);

				if (attr == null)
					throw new MongoCollectionNameMissingException(typeof(T));

				return attr.CollectionName;
			}
		}

		/// <summary>
		/// Gets the collection for the MongoServices model.
		/// </summary>
		protected MongoCollection<T> Collection
		{
			get
			{
				if (_collection == null)
				{
					_collection = Database.GetCollection<T>(CollectionName);
				}

				return _collection;
			}
		}
		#endregion

		#region Internal Properties
		internal static GlobalConfigContainer GlobalConfig
		{
			get
			{
				return GlobalConfigContainer.Instance;
			}
		}

		internal static RepositoryConfigContainer<MongoServicesRepository<T>, T> RepositoryConfig
		{
			get
			{
				return RepositoryConfigContainer<MongoServicesRepository<T>, T>.Instance;
			}
		}
		#endregion

		#region Private Properties
		/// <summary>
		/// Gets the MongoDatabase to be used by the <see cref="MongoServicesRepository&lt;T&gt;.Collection"/> property.
		/// </summary>
		private MongoDatabase Database
		{
			get
			{
				var mongoUrlProvider = RepositoryConfig.MongoUrlProvider == null ? GlobalConfig.MongoUrlProvider : RepositoryConfig.MongoUrlProvider;

				return MongoDatabase.Create(mongoUrlProvider());
			}
		}
		#endregion

		#region Static Methods
		/// <summary>
		/// Sets the MongoUrl provider for the repository.
		/// </summary>
		/// <param name="provider">A <code>Func&lt;MongoUrl&gt;</code> that will return the appropriate MongoUrl.</param>
		public static void SetMongoUrlProvider(Func<MongoUrl> provider)
		{
			 RepositoryConfig.MongoUrlProvider = provider;
		}
		#endregion
	}
}
